/*
This is part of Screenbar, which is based in part on the Litestep
shell source code.

Copyright (C) 2008-2009 Jim Babcock
Copyright (C) 1997-2009 The LiteStep Development Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#include "stdafx.h"

DragState dragState;

DragState::DragState()
{
	state = notDragging;
	window = NULL;
}

DragState::~DragState()
{
	if(window) {
		delete window;
		window = NULL;
	}
}

void DragState::anchorDrag(ScreenbarWindow *sourceWindow, LayoutReference *anchor, Point offset)
{
	SetCapture(sourceWindow->getWindow());
	this->state = anchored;
	this->anchor = anchor;
	this->anchorCursorPos = getCursorPos(); // FIXME
	this->anchorOffset = offset;
	
	this->draggedItem = new DragItem(anchor);
}

bool DragState::isAnchored() const
{
	return (state == anchored);
}

Point DragState::getAnchor() const
{
	return anchorOffset;
}

void DragState::beginDrag()
{
	if(state!=anchored)
		return;
	
	LayoutCacheNode *node = anchor->getNode();
	if(!node) {
		// The element this drag was anchored to no longer exists. Take what's
		// now where the cursor started instead.
		delete anchor;
		
		anchor = getNodeAtPoint(anchorCursorPos);
		if(!anchor || !anchor->getNode()) {
			cancelDrag();
			return;
		}
		node = anchor->getNode();
		if(!node->element->draggable) {
			cancelDrag();
			return;
		}
	}
	
	state = dragging;
	dragContext = node->context;
	window = new DragWindow(node, anchorOffset);
}

void DragState::beginDrag(DragItem *dragged, ElementContext dragContext)
{
	this->state = dragging;
	this->draggedItem = dragged;
	this->dragContext = dragContext;
}

bool DragState::isDragging() const
{
	return (state == dragging);
}

void DragState::cancelDrag()
{
	SetCapture(NULL);
	state = notDragging;
	
	if(draggedItem) {
		delete draggedItem;
		draggedItem = NULL;
	}
	if(anchor) {
		delete anchor;
		anchor = NULL;
	}
	if(window) {
		delete window;
		window = NULL;
	}
}

void DragState::updateHover()
{
	Point cursorPos = getCursorPos();
	ScreenbarPanel *panel = getPanelAtPoint(cursorPos);
	if(!panel) return;
	LayoutReference *ref = getNodeAtPoint(cursorPos);
	if(!ref) return;
	
	LayoutCacheNode *node = ref->getNode();
	delete ref;
	if(!node) return;
	
	node->element->hoverDragged(node, draggedItem);
}

void DragState::drop()
{
	Point cursorPos = getCursorPos();
	LayoutReference *dropTargetRef = getNodeAtPoint(cursorPos);
	ScreenbarPanel *targetPanel = getPanelAtPoint(cursorPos);
	
	if(dropTargetRef) {
		drop(targetPanel, dropTargetRef);
		delete dropTargetRef;
	} else {
		cancelDrag();
	}
}

void DragState::drop(ScreenbarPanel *targetPanel, LayoutReference *target)
{
	state = dropping;
	LayoutCacheNode *node = target->getNode();
	if(!node) {
		cancelDrag();
		return;
	}
	
	dropContext = node->context;
	node->element->dropOn(node, draggedItem);
	cancelDrag();
}

bool DragState::isDropping() const
{
	return (state == dropping);
}

ElementContext DragState::getContext() const
{
	return dragContext;
}

ElementContext DragState::getDropContext() const
{
	return dropContext;
}

/////////////////////////////////////////////////////////////////////////////

DragItem::DragItem(LayoutReference *anchor)
{
	LayoutCacheNode *node = anchor->getNode();
	this->prefix = node->element->prefix;
}

DragItem::~DragItem()
{
}

string DragItem::getPrefix()
{
	return prefix;
}

/////////////////////////////////////////////////////////////////////////////

void LayoutElement::hoverDragged(LayoutCacheNode *node, DragItem *item)
{
	string hoverCmdName = string("OnHover_") + item->getPrefix();
	string hoverCmd = getConfigLine(hoverCmdName.c_str(), "", prefix.c_str());
	
	if(hoverCmd == "") {
		if(node->parent)
			node->parent->element->hoverDragged(node->parent, item);
	} else {
		LSExecute(node->context.window->getWindow(), hoverCmd.c_str(), SW_SHOWNORMAL);
	}
}

void LayoutElement::dropOn(LayoutCacheNode *node, DragItem *item)
{
	string dropCmdName = string("OnDrop_") + item->getPrefix();
	string dropCmd = getConfigLine(dropCmdName.c_str(), "", prefix.c_str());
	
	if(dropCmd == "") {
		if(node->parent)
			node->parent->element->dropOn(node->parent, item);
	} else {
		LSExecute(node->context.window->getWindow(), dropCmd.c_str(), SW_SHOWNORMAL);
	}
}

